package auth

import (
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"go-admin-official/guard"
	"go-admin-official/models"
	"go-admin-official/modules/config"
	"go-admin-official/modules/discuss"
	"go-admin-official/modules/logger"
	"golang.org/x/crypto/bcrypt"
	"net/http"
)

const SessionKey = "GOADMIN_OFFICIAL_SESS"

func Login(ctx *gin.Context, param guard.SignInParam) (int, string) {
	user := models.Users().Check(param.GetAccountType(), param.Account)
	if user.Empty() {
		return http.StatusBadRequest, "用户不存在"
	}
	if !comparePassword(param.Password, user.Password) {
		return http.StatusUnauthorized, "账号与密码不匹配"
	}

	user.UpdateLoginTime()

	session := sessions.Default(ctx)
	session.Set(SessionKey, getToken(user))
	session.Options(sessions.Options{
		Path:     "/",
		Domain:   "",
		MaxAge:   int(config.Get().TokenSessionTime),
		Secure:   false,
		HttpOnly: false,
	})
	_ = session.Save()

	return 0, "ok"
}

func ApiLogin(ctx *gin.Context, param guard.SignInParam) (int, string, string, string) {
	user := models.Users().Check(param.GetAccountType(), param.Account)
	if user.Empty() {
		return http.StatusBadRequest, "用户不存在", "", ""
	}
	if !comparePassword(param.Password, user.Password) {
		return http.StatusUnauthorized, "账号与密码不匹配", "", ""
	}

	user.UpdateLoginTime()

	token := getToken(user)

	session := sessions.Default(ctx)
	session.Set(SessionKey, token)
	session.Options(sessions.Options{
		Path:     "/",
		Domain:   "",
		MaxAge:   int(config.Get().TokenSessionTime),
		Secure:   false,
		HttpOnly: false,
	})
	_ = session.Save()

	return 0, "ok", token, user.UserName
}

func Register(param guard.SignUpParam) (int, string, int64) {

	if !models.Users().Exist(param.Name, param.Email) {
		return http.StatusBadRequest, "账号已存在", 0
	}

	user := models.Users()
	user.Name = param.Name
	user.UserName = param.Name
	user.Email = param.Email
	user.Password = encodePassword([]byte(param.Password))

	user, err := user.Insert()

	if err != nil {
		logger.Error(err)
		return http.StatusInternalServerError, "服务器错误", 0
	}

	// 注册论坛
	go func() {
		defer func() {
			if e := recover(); e != nil {
				logger.Error("register discuss recover error", e)
			}
		}()
		err = discuss.RegisterUser(discuss.RegisterParam{
			Name:     param.Name,
			Email:    param.Email,
			Password: param.Password,
			Username: param.Name,
		})

		if err != nil {
			logger.Error("register discuss error", err)
		}
	}()

	return 0, "ok", user.Id
}

func Logout(ctx *gin.Context) (int, string) {
	session := sessions.Default(ctx)
	session.Delete(SessionKey)
	_ = session.Save()
	return 0, "ok"
}

func comparePassword(comPwd, pwdHash string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(pwdHash), []byte(comPwd))
	return err == nil
}

func encodePassword(pwd []byte) string {
	hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.DefaultCost)
	if err != nil {
		return ""
	}
	return string(hash[:])
}
